﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Net;

namespace Server
{
    public class SocketHelper
    {
        private readonly AutoResetEvent _flipFlop = new AutoResetEvent(false);
        private readonly List<Socket> _clientSockets = new List<Socket>();
        private readonly Unit _unit = new Unit();

        public void CreateSocket(object start)
        {
            Socket serverSocket = (Socket)start;
            while (true)
            {
                _flipFlop.Reset();
                serverSocket.BeginAccept(AcceptCallback, serverSocket);
                _flipFlop.WaitOne();
            }
        }

        private void AcceptCallback(IAsyncResult ar)
        {
            _flipFlop.Set();
            Socket listener = (Socket)ar.AsyncState;
            Socket socket = listener.EndAccept(ar);

            _clientSockets.Add(socket);

            _unit.MsgBuffer = new byte[65535];
            List<object> state = new List<object> { socket, _unit.MsgBuffer };
            socket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, state);
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            List<object> state = (List<object>)ar.AsyncState;
            Socket socket = (Socket)state[0];
            socket.EndReceive(ar);

            MessagePackage msgPackage = JsonSerializer<MessagePackage>.GetJsonToObject(_unit.MsgBuffer);
            List<object> objList = new List<object> { socket, _unit.MsgBuffer };

            switch (msgPackage.ConnectType)
            {
                case (int)ConnectType.LoginOn:
                    if (msgPackage.Msg != string.Empty)
                    {
                        string[] msgArray = msgPackage.Msg.Split(';');
                        if (msgArray[0] == "admin" && msgArray[1] == "21232F297A57A5A743894A0E4A801FC3")
                        {
                            _unit.OnlineUser.Add(msgArray[2]);
                            msgPackage.ConnectType = 1;
                            msgPackage.Msg = JsonSerializer<List<string>>.GetObjectJsonTo(_unit.OnlineUser);

                            _unit.MsgSend = new Byte[65535];
                            _unit.MsgBuffer = new byte[65535];
                            _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(msgPackage));
                            foreach (var clientSocket in _clientSockets)
                            {
                                clientSocket.BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);

                                clientSocket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, objList);
                            }
                        }
                        else
                        {
                            msgPackage.ConnectType = 1; msgPackage.Msg = "false";

                            _unit.MsgSend = new Byte[65535];
                            _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(msgPackage));
                            _clientSockets[0].BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);
                            _clientSockets.Remove(_clientSockets[0]);
                        }
                    }
                    break;
                case (int)ConnectType.GroupMsg:
                    _unit.MsgSend = new Byte[65535];
                    _unit.MsgBuffer = new byte[65535];
                    _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(msgPackage));
                    foreach (var clientSocket in _clientSockets)
                    {
                        clientSocket.BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);

                        clientSocket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, objList);
                    }
                    break;
                case (int)ConnectType.Exit:
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Disconnect(false);
                    socket.Close();

                    _clientSockets.Remove(socket);
                    _unit.OnlineUser.Remove(msgPackage.Name);
                    _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(new MessagePackage() { ConnectType = (int)ConnectType.Exit, Name = msgPackage.Name, Msg = JsonSerializer<List<string>>.GetObjectJsonTo(_unit.OnlineUser) }));
                    foreach (var clientSocket in _clientSockets)
                    {
                        clientSocket.BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);

                        clientSocket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, objList);
                    }
                    break;
                case (int)ConnectType.LaunchWhisper:
                    Socket siliaoSocket = _clientSockets[Convert.ToInt32(msgPackage.Msg)];
                    string userName = _unit.OnlineUser[Convert.ToInt32(msgPackage.Msg)];
                    _unit.MsgSend = new Byte[65535];
                    _unit.MsgBuffer = new byte[65535];
                    IPEndPoint ipEnd = (IPEndPoint)(siliaoSocket.RemoteEndPoint);
                    _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(new MessagePackage { ConnectType = (int)ConnectType.LaunchWhisper, Name = userName, Msg = ipEnd.Address.ToString() + ":" + ipEnd.Port }));
                    siliaoSocket.BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);

                    siliaoSocket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, objList);
                    break;

                case (int)ConnectType.WhisperMsg:
                    string hostAndPort = msgPackage.Msg.Split(';')[0];
                    string host = hostAndPort.Split(':')[0];
                    string prot = hostAndPort.Split(':')[1];
                    EndPoint ep = new DnsEndPoint(host, Convert.ToInt32(prot));
                    siliaoSocket = _clientSockets.Where(I => I.LocalEndPoint == ep).FirstOrDefault();

                    _unit.MsgSend = new Byte[65535];
                    _unit.MsgBuffer = new byte[65535];
                    _unit.MsgSend = Encoding.UTF8.GetBytes(JsonSerializer<MessagePackage>.GetObjectJsonTo(new MessagePackage { ConnectType = (int)ConnectType.LaunchWhisper, Msg = msgPackage.Msg }));
                    siliaoSocket.BeginSend(_unit.MsgSend, 0, _unit.MsgSend.Length, SocketFlags.None, null, null);

                    siliaoSocket.BeginReceive(_unit.MsgBuffer, 0, _unit.MsgBuffer.Length, SocketFlags.None, ReceiveCallback, objList);
                    break;
            }
        }
    }
}
